home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d927.lha / Telnet / src / telnet.c < prev    next >
C/C++ Source or Header  |  1993-10-07  |  39KB  |  1,905 lines

  1. /*
  2.  * Copyright (c) 1988, 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted provided
  6.  * that: (1) source distributions retain this entire copyright notice and
  7.  * comment, and (2) distributions including binaries display the following
  8.  * acknowledgement:  ``This product includes software developed by the
  9.  * University of California, Berkeley and its contributors'' in the
  10.  * documentation or other materials provided with the distribution and in
  11.  * all advertising materials mentioning features or use of this software.
  12.  * Neither the name of the University nor the names of its contributors may
  13.  * be used to endorse or promote products derived from this software without
  14.  * specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  16.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  17.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char sccsid[] = "@(#)telnet.c    5.51 (Berkeley) 9/14/90";
  22. #endif /* not lint */
  23.  
  24. #include <sys/types.h>
  25. #include <dos/dos.h>
  26.  
  27. #ifdef    KERBEROS
  28. #include <sys/socket.h>
  29. #include <netinet/in.h>
  30. #include <kerberosIV/des.h>
  31. #include <kerberosIV/krb.h>
  32. #include "krb4-proto.h"
  33. #endif
  34.  
  35. #include <arpa/telnet.h>
  36.  
  37. #include <string.h>
  38.  
  39. #include <ctype.h>
  40.  
  41. #include "ring.h"
  42.  
  43. #include "defines.h"
  44. #include "externs.h"
  45. #include "types.h"
  46. #include "general.h"
  47.  
  48. #define    strip(x)    ((x)&0x7f)
  49.  
  50. extern char *env_getvalue();
  51.  
  52. static char    subbuffer[SUBBUFSIZE],
  53.         *subpointer, *subend;     /* buffer for sub-options */
  54. #define    SB_CLEAR()    subpointer = subbuffer;
  55. #define    SB_TERM()    subend = subpointer;
  56. #define    SB_ACCUM(c)    if (subpointer < (subbuffer+sizeof subbuffer)) { \
  57.                 *subpointer++ = (c); \
  58.             }
  59.  
  60. char    options[256];        /* The combined options */
  61. char    do_dont_resp[256];
  62. char    will_wont_resp[256];
  63.  
  64. int
  65.     connected,
  66.     showoptions,
  67.     ISend,        /* trying to send network data in */
  68.     debug = 0,
  69.     crmod,
  70.     netdata,    /* Print out network data flow */
  71.     crlf,        /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
  72.     telnetport,
  73.     SYNCHing,    /* we are in TELNET SYNCH mode */
  74.     flushout,    /* flush output */
  75.     autoflush = 0,    /* flush output when interrupting? */
  76.     autosynch,    /* send interrupt characters with SYNCH? */
  77.     localflow,    /* we handle flow control locally */
  78.     localchars,    /* we recognize interrupt/quit */
  79.     donelclchars,    /* the user has set "localchars" */
  80.     donebinarytoggle,    /* the user has put us in binary */
  81.     dontlecho,    /* do we suppress local echoing right now? */
  82.     globalmode;
  83.  
  84. char *prompt = 0;
  85.  
  86. cc_t escape;
  87.  
  88. /*
  89.  * Telnet receiver states for fsm
  90.  */
  91. #define    TS_DATA        0
  92. #define    TS_IAC        1
  93. #define    TS_WILL        2
  94. #define    TS_WONT        3
  95. #define    TS_DO        4
  96. #define    TS_DONT        5
  97. #define    TS_CR        6
  98. #define    TS_SB        7        /* sub-option collection */
  99. #define    TS_SE        8        /* looking for sub-option end */
  100.  
  101. static int    telrcv_state;
  102.  
  103. jmp_buf    toplevel = { 0 };
  104. jmp_buf    peerdied;
  105.  
  106. int    flushline;
  107. int    linemode;
  108.  
  109. /*
  110.  * The following are some clocks used to decide how to interpret
  111.  * the relationship between various variables.
  112.  */
  113.  
  114. Clocks clocks;
  115.  
  116. /*
  117.  * Initialize telnet environment.
  118.  */
  119.  
  120. init_telnet()
  121. {
  122.     env_init();
  123.  
  124.     SB_CLEAR();
  125.     ClearArray(options);
  126.  
  127.     connected = ISend = localflow = donebinarytoggle = 0;
  128.  
  129.     SYNCHing = 0;
  130.  
  131.     /* Don't change NetTrace */
  132.  
  133.     escape = CONTROL(']');
  134.     flushline = 1;
  135.     telrcv_state = TS_DATA;
  136. }
  137.  
  138.  
  139.  
  140. /*
  141.  * These routines are in charge of sending option negotiations
  142.  * to the other side.
  143.  *
  144.  * The basic idea is that we send the negotiation if either side
  145.  * is in disagreement as to what the current state should be.
  146.  */
  147.  
  148. send_do(c, init)
  149. register int c, init;
  150. {
  151.     if (init) {
  152.     if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
  153.                 my_want_state_is_do(c))
  154.         return;
  155.     set_my_want_state_do(c);
  156.     do_dont_resp[c]++;
  157.     }
  158.     NET2ADD(IAC, DO);
  159.     NETADD(c);
  160.     printoption("SENT", "do", c);
  161. }
  162.  
  163. void
  164. send_dont(c, init)
  165. register int c, init;
  166. {
  167.     if (init) {
  168.     if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
  169.                 my_want_state_is_dont(c))
  170.         return;
  171.     set_my_want_state_dont(c);
  172.     do_dont_resp[c]++;
  173.     }
  174.     NET2ADD(IAC, DONT);
  175.     NETADD(c);
  176.     printoption("SENT", "dont", c);
  177. }
  178.  
  179. void
  180. send_will(c, init)
  181. register int c, init;
  182. {
  183.     if (init) {
  184.     if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
  185.                 my_want_state_is_will(c))
  186.         return;
  187.     set_my_want_state_will(c);
  188.     will_wont_resp[c]++;
  189.     }
  190.     NET2ADD(IAC, WILL);
  191.     NETADD(c);
  192.     printoption("SENT", "will", c);
  193. }
  194.  
  195. void
  196. send_wont(c, init)
  197. register int c, init;
  198. {
  199.     if (init) {
  200.     if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
  201.                 my_want_state_is_wont(c))
  202.         return;
  203.     set_my_want_state_wont(c);
  204.     will_wont_resp[c]++;
  205.     }
  206.     NET2ADD(IAC, WONT);
  207.     NETADD(c);
  208.     printoption("SENT", "wont", c);
  209. }
  210.  
  211.  
  212. void
  213. willoption(option)
  214.     int option;
  215. {
  216.     int new_state_ok = 0;
  217.  
  218.     if (do_dont_resp[option]) {
  219.         --do_dont_resp[option];
  220.         if (do_dont_resp[option] && my_state_is_do(option))
  221.         --do_dont_resp[option];
  222.     }
  223.  
  224.     if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
  225.  
  226.         switch (option) {
  227.  
  228.         case TELOPT_ECHO:
  229.         case TELOPT_BINARY:
  230.         case TELOPT_SGA:
  231.         settimer(modenegotiated);
  232.         /* FALL THROUGH */
  233.         case TELOPT_STATUS:
  234.         new_state_ok = 1;
  235.         break;
  236.  
  237.         case TELOPT_TM:
  238.         if (flushout)
  239.             flushout = 0;
  240.         /*
  241.          * Special case for TM.  If we get back a WILL,
  242.          * pretend we got back a WONT.
  243.          */
  244.         set_my_want_state_dont(option);
  245.         set_my_state_dont(option);
  246.         return;            /* Never reply to TM will's/wont's */
  247.  
  248.         case TELOPT_LINEMODE:
  249.         default:
  250.         break;
  251.         }
  252.  
  253.         if (new_state_ok) {
  254.         set_my_want_state_do(option);
  255.         send_do(option, 0);
  256.         setconnmode(0);        /* possibly set new tty mode */
  257.         } else {
  258.         do_dont_resp[option]++;
  259.         send_dont(option, 0);
  260.         }
  261.     }
  262.     set_my_state_do(option);
  263. }
  264.  
  265. void
  266. wontoption(option)
  267.     int option;
  268. {
  269.     if (do_dont_resp[option]) {
  270.         --do_dont_resp[option];
  271.         if (do_dont_resp[option] && my_state_is_dont(option))
  272.         --do_dont_resp[option];
  273.     }
  274.  
  275.     if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
  276.  
  277.         switch (option) {
  278.  
  279.         case TELOPT_ECHO:
  280.         settimer(modenegotiated);
  281.         break;
  282.  
  283.         case TELOPT_TM:
  284.         if (flushout)
  285.             flushout = 0;
  286.         set_my_want_state_dont(option);
  287.         set_my_state_dont(option);
  288.         return;        /* Never reply to TM will's/wont's */
  289.  
  290.         default:
  291.         break;
  292.         }
  293.         set_my_want_state_dont(option);
  294.         if (my_state_is_do(option))
  295.         send_dont(option, 0);
  296.         setconnmode(0);            /* Set new tty mode */
  297.     } else if (option == TELOPT_TM) {
  298.         /*
  299.          * Special case for TM.
  300.          */
  301.         if (flushout)
  302.         flushout = 0;
  303.         set_my_want_state_dont(option);
  304.     }
  305.     set_my_state_dont(option);
  306. }
  307.  
  308. static void
  309. dooption(option)
  310.     int option;
  311. {
  312.     int new_state_ok = 0;
  313.  
  314.     if (will_wont_resp[option]) {
  315.         --will_wont_resp[option];
  316.         if (will_wont_resp[option] && my_state_is_will(option))
  317.         --will_wont_resp[option];
  318.     }
  319.  
  320.     if (will_wont_resp[option] == 0) {
  321.       if (my_want_state_is_wont(option)) {
  322.  
  323.         switch (option) {
  324.  
  325.         case TELOPT_TM:
  326.         /*
  327.          * Special case for TM.  We send a WILL, but pretend
  328.          * we sent WONT.
  329.          */
  330.         send_will(option, 0);
  331.         set_my_want_state_wont(TELOPT_TM);
  332.         set_my_state_wont(TELOPT_TM);
  333.         return;
  334.  
  335.         case TELOPT_BINARY:        /* binary mode */
  336.         case TELOPT_NAWS:        /* window size */
  337.         case TELOPT_TSPEED:        /* terminal speed */
  338.         case TELOPT_LFLOW:        /* local flow control */
  339.         case TELOPT_TTYPE:        /* terminal type option */
  340.         case TELOPT_SGA:        /* no big deal */
  341.         case TELOPT_ENVIRON:    /* environment variable option */
  342.         new_state_ok = 1;
  343.         break;
  344.  
  345.         case TELOPT_XDISPLOC:    /* X Display location */
  346.         if (env_getvalue("DISPLAY"))
  347.             new_state_ok = 1;
  348.         break;
  349.  
  350.         case TELOPT_LINEMODE:
  351.         set_my_want_state_will(TELOPT_LINEMODE);
  352.         send_will(option, 0);
  353.         set_my_state_will(TELOPT_LINEMODE);
  354.         slc_init();
  355.         return;
  356.  
  357.         case TELOPT_ECHO:        /* We're never going to echo... */
  358.         default:
  359.         break;
  360.         }
  361.  
  362.         if (new_state_ok) {
  363.         set_my_want_state_will(option);
  364.         send_will(option, 0);
  365.         setconnmode(0);            /* Set new tty mode */
  366.         } else {
  367.         will_wont_resp[option]++;
  368.         send_wont(option, 0);
  369.         }
  370.       } else {
  371.         /*
  372.          * Handle options that need more things done after the
  373.          * other side has acknowledged the option.
  374.          */
  375.         switch (option) {
  376.         case TELOPT_LINEMODE:
  377.         set_my_state_will(option);
  378.         slc_init();
  379.         send_do(TELOPT_SGA, 0);
  380.         return;
  381.         }
  382.       }
  383.     }
  384.     set_my_state_will(option);
  385. }
  386.  
  387. static void
  388. dontoption(option)
  389.     int option;
  390. {
  391.  
  392.     if (will_wont_resp[option]) {
  393.         --will_wont_resp[option];
  394.         if (will_wont_resp[option] && my_state_is_wont(option))
  395.         --will_wont_resp[option];
  396.     }
  397.  
  398.     if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
  399.         switch (option) {
  400.         case TELOPT_LINEMODE:
  401.         linemode = 0;    /* put us back to the default state */
  402.         break;
  403.         }
  404.         /* we always accept a DONT */
  405.         set_my_want_state_wont(option);
  406.         if (my_state_is_will(option))
  407.         send_wont(option, 0);
  408.         setconnmode(0);            /* Set new tty mode */
  409.     }
  410.     set_my_state_wont(option);
  411. }
  412.  
  413. /*
  414.  * Given a buffer returned by tgetent(), this routine will turn
  415.  * the pipe seperated list of names in the buffer into an array
  416.  * of pointers to null terminated names.  We toss out any bad,
  417.  * duplicate, or verbose names (names with spaces).
  418.  */
  419.  
  420. static char *unknown[] = { "UNKNOWN", 0 };
  421.  
  422. char **
  423. mklist(buf, name)
  424. char *buf, *name;
  425. {
  426.     register int n;
  427.     register char c, *cp, **argvp, *cp2, **argv;
  428.     char *malloc();
  429.  
  430.     if (name) {
  431.         if (strlen(name) > 40)
  432.             name = 0;
  433.         else {
  434.             unknown[0] = name;
  435.             upcase(name);
  436.         }
  437.     }
  438.     /*
  439.      * Count up the number of names.
  440.      */
  441.     for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
  442.         if (*cp == '|')
  443.             n++;
  444.     }
  445.     /*
  446.      * Allocate an array to put the name pointers into
  447.      */
  448.     argv = (char **)malloc((n+3)*sizeof(char *));
  449.     if (argv == 0)
  450.         return(unknown);
  451.  
  452.     /*
  453.      * Fill up the array of pointers to names.
  454.      */
  455.     *argv = 0;
  456.     argvp = argv+1;
  457.     n = 0;
  458.     for (cp = cp2 = buf; (c = *cp);  cp++) {
  459.         if (c == '|' || c == ':') {
  460.             *cp++ = '\0';
  461.             /*
  462.              * Skip entries that have spaces or are over 40
  463.              * characters long.  If this is our environment
  464.              * name, then put it up front.  Otherwise, as
  465.              * long as this is not a duplicate name (case
  466.              * insensitive) add it to the list.
  467.              */
  468.             if (n || (cp - cp2 > 41))
  469.                 ;
  470.             else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
  471.                 *argv = cp2;
  472.             else if (is_unique(cp2, argv+1, argvp))
  473.                 *argvp++ = cp2;
  474.             if (c == ':')
  475.                 break;
  476.             /*
  477.              * Skip multiple delimiters. Reset cp2 to
  478.              * the beginning of the next name. Reset n,
  479.              * the flag for names with spaces.
  480.              */
  481.             while ((c = *cp) == '|')
  482.                 cp++;
  483.             cp2 = cp;
  484.             n = 0;
  485.         }
  486.         /*
  487.          * Skip entries with spaces or non-ascii values.
  488.          * Convert lower case letters to upper case.
  489.          */
  490.         if ((c == ' ') || !isascii(c))
  491.             n = 1;
  492.         else if (islower(c))
  493.             *cp = toupper(c);
  494.     }
  495.     
  496.     /*
  497.      * Check for an old V6 2 character name.  If the second
  498.      * name points to the beginning of the buffer, and is
  499.      * only 2 characters long, move it to the end of the array.
  500.      */
  501.     if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
  502.         *argvp++ = buf;
  503.         cp = *argv++;
  504.         *argv = cp;
  505.     }
  506.  
  507.     /*
  508.      * Duplicate last name, for TTYPE option, and null
  509.      * terminate the array.  If we didn't find a match on
  510.      * our terminal name, put that name at the beginning.
  511.      */
  512.     cp = *(argvp-1);
  513.     *argvp++ = cp;
  514.     *argvp = 0;
  515.  
  516.     if (*argv == 0) {
  517.         if (name)
  518.             *argv = name;
  519.         else
  520.             argv++;
  521.     }
  522.     if (*argv)
  523.         return(argv);
  524.     else
  525.         return(unknown);
  526. }
  527.  
  528. is_unique(name, as, ae)
  529. register char *name, **as, **ae;
  530. {
  531.     register char **ap;
  532.     register int n;
  533.  
  534.     n = strlen(name) + 1;
  535.     for (ap = as; ap < ae; ap++)
  536.         if (strncasecmp(*ap, name, n) == 0)
  537.             return(0);
  538.     return (1);
  539. }
  540.  
  541. #ifdef    TERMCAP
  542. char termbuf[1024];
  543. /*ARGSUSED*/
  544. setupterm(tname, fd, errp)
  545. char *tname;
  546. int fd, *errp;
  547. {
  548. #if 0
  549.     if (tgetent(termbuf, tname) == 1) {
  550.         termbuf[1023] = '\0';
  551.         if (errp)
  552.             *errp = 1;
  553.         return(0);
  554.     }
  555. #endif
  556.     if (errp)
  557.         *errp = 0;
  558.     return(-1);
  559. }
  560. #else
  561. #define    termbuf    ttytype
  562. extern char ttytype[];
  563. #endif
  564.  
  565. char *
  566. gettermname()
  567. {
  568.     char *tname;
  569.     static int first = 1;
  570.     static char **tnamep;
  571.     static char **next;
  572.     int err;
  573.  
  574.     if (first) {
  575.         first = 0;
  576.         if ((tname = env_getvalue("TERM")) &&
  577.                 (setupterm(tname, 1, &err) == 0)) {
  578.             tnamep = mklist(termbuf, tname);
  579.         } else {
  580.             if (tname && (strlen(tname) <= 40)) {
  581.                 unknown[0] = tname;
  582.                 upcase(tname);
  583.             }
  584.             tnamep = unknown;
  585.         }
  586.         next = tnamep;
  587.     }
  588.     if (*next == 0)
  589.         next = tnamep;
  590.     return(*next++);
  591. }
  592. /*
  593.  * suboption()
  594.  *
  595.  *    Look at the sub-option buffer, and try to be helpful to the other
  596.  * side.
  597.  *
  598.  *    Currently we recognize:
  599.  *
  600.  *        Terminal type, send request.
  601.  *        Terminal speed (send request).
  602.  *        Local flow control (is request).
  603.  *        Linemode
  604.  */
  605.  
  606. static void
  607. suboption()
  608. {
  609.     printsub('<', subbuffer, subend-subbuffer+2);
  610.     switch (subbuffer[0]&0xff) {
  611.     case TELOPT_TTYPE:
  612.     if (my_want_state_is_wont(TELOPT_TTYPE))
  613.         return;
  614.     if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
  615.         ;
  616.     } else {
  617.         char *name;
  618.         char temp[50];
  619.         int len;
  620.  
  621.         name = gettermname();
  622.         len = strlen(name) + 4 + 2;
  623.         if (len < NETROOM()) {
  624.         sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
  625.                 TELQUAL_IS, name, IAC, SE);
  626.         ring_supply_data(&netoring, temp, len);
  627.         printsub('>', &temp[2], len-2);
  628.         } else {
  629.         ExitString("No room in buffer for terminal type.\n", 1);
  630.         /*NOTREACHED*/
  631.         }
  632.     }
  633.     break;
  634.     case TELOPT_TSPEED:
  635.     if (my_want_state_is_wont(TELOPT_TSPEED))
  636.         return;
  637.     if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
  638.         long ospeed, ispeed;
  639.         char temp[50];
  640.         int len;
  641.  
  642. #if defined(MCH_AMIGA) || defined(_AMIGA) 
  643.          ospeed = 9600;
  644.          ispeed = 9600;
  645. #else
  646.         TerminalSpeeds(&ispeed, &ospeed);
  647. #endif
  648.         sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
  649.             TELQUAL_IS, ospeed, ispeed, IAC, SE);
  650.         len = strlen(temp+4) + 4;    /* temp[3] is 0 ... */
  651.  
  652.         if (len < NETROOM()) {
  653.         ring_supply_data(&netoring, temp, len);
  654.         printsub('>', temp+2, len - 2);
  655.         }
  656. /*@*/        else printf("lm_will: not enough room in buffer\n");
  657.     }
  658.     break;
  659.     case TELOPT_LFLOW:
  660.     if (my_want_state_is_wont(TELOPT_LFLOW))
  661.         return;
  662.     if ((subbuffer[1]&0xff) == 1) {
  663.         localflow = 1;
  664.     } else if ((subbuffer[1]&0xff) == 0) {
  665.         localflow = 0;
  666.     }
  667.     setcommandmode();
  668.     setconnmode(0);
  669.     break;
  670.  
  671.     case TELOPT_LINEMODE:
  672.     if (my_want_state_is_wont(TELOPT_LINEMODE))
  673.         return;
  674.     switch (subbuffer[1]&0xff) {
  675.     case WILL:
  676.         lm_will(&subbuffer[2], subend - &subbuffer[2]);
  677.         break;
  678.     case WONT:
  679.         lm_wont(&subbuffer[2], subend - &subbuffer[2]);
  680.         break;
  681.     case DO:
  682.         lm_do(&subbuffer[2], subend - &subbuffer[2]);
  683.         break;
  684.     case DONT:
  685.         lm_dont(&subbuffer[2], subend - &subbuffer[2]);
  686.         break;
  687.     case LM_SLC:
  688.         slc(&subbuffer[2], subend - &subbuffer[2]);
  689.         break;
  690.     case LM_MODE:
  691.         lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
  692.         break;
  693.     default:
  694.         break;
  695.     }
  696.     break;
  697.  
  698.     case TELOPT_ENVIRON:
  699.     switch(subbuffer[1]&0xff) {
  700.     case TELQUAL_IS:
  701.     case TELQUAL_INFO:
  702.         if (my_want_state_is_dont(TELOPT_ENVIRON))
  703.         return;
  704.         break;
  705.     case TELQUAL_SEND:
  706.         if (my_want_state_is_wont(TELOPT_ENVIRON)) {
  707.         return;
  708.         }
  709.         break;
  710.     default:
  711.         return;
  712.     }
  713.     env_opt(&subbuffer[1], subend - &subbuffer[1]);
  714.     break;
  715.  
  716.     case TELOPT_XDISPLOC:
  717.     if (my_want_state_is_wont(TELOPT_XDISPLOC))
  718.         return;
  719.     if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
  720.         char temp[50], *dp;
  721.         int len;
  722.  
  723.         if ((dp = env_getvalue("DISPLAY")) == NULL) {
  724.         /*
  725.          * Something happened, we no longer have a DISPLAY
  726.          * variable.  So, turn off the option.
  727.          */
  728.         send_wont(TELOPT_XDISPLOC, 1);
  729.         break;
  730.         }
  731.         sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
  732.             TELQUAL_IS, dp, IAC, SE);
  733.         len = strlen(temp+4) + 4;    /* temp[3] is 0 ... */
  734.  
  735.         if (len < NETROOM()) {
  736.         ring_supply_data(&netoring, temp, len);
  737.         printsub('>', temp+2, len - 2);
  738.         }
  739. /*@*/        else printf("lm_will: not enough room in buffer\n");
  740.     }
  741.     break;
  742.  
  743.     default:
  744.     break;
  745.     }
  746. }
  747.  
  748. static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
  749.  
  750. lm_will(cmd, len)
  751. unsigned char *cmd;
  752. {
  753.     if (len < 1) {
  754. /*@*/    printf("lm_will: no command!!!\n");    /* Should not happen... */
  755.     return;
  756.     }
  757.     switch(cmd[0]) {
  758.     case LM_FORWARDMASK:    /* We shouldn't ever get this... */
  759.     default:
  760.     str_lm[3] = DONT;
  761.     str_lm[4] = cmd[0];
  762.     if (NETROOM() > sizeof(str_lm)) {
  763.         ring_supply_data(&netoring, str_lm, sizeof(str_lm));
  764.         printsub('>', &str_lm[2], sizeof(str_lm)-2);
  765.     }
  766. /*@*/    else printf("lm_will: not enough room in buffer\n");
  767.     break;
  768.     }
  769. }
  770.  
  771. lm_wont(cmd, len)
  772. unsigned char *cmd;
  773. {
  774.     if (len < 1) {
  775. /*@*/    printf("lm_wont: no command!!!\n");    /* Should not happen... */
  776.     return;
  777.     }
  778.     switch(cmd[0]) {
  779.     case LM_FORWARDMASK:    /* We shouldn't ever get this... */
  780.     default:
  781.     /* We are always DONT, so don't respond */
  782.     return;
  783.     }
  784. }
  785.  
  786. lm_do(cmd, len)
  787. unsigned char *cmd;
  788. {
  789.     if (len < 1) {
  790. /*@*/    printf("lm_do: no command!!!\n");    /* Should not happen... */
  791.     return;
  792.     }
  793.     switch(cmd[0]) {
  794.     case LM_FORWARDMASK:
  795.     default:
  796.     str_lm[3] = WONT;
  797.     str_lm[4] = cmd[0];
  798.     if (NETROOM() > sizeof(str_lm)) {
  799.         ring_supply_data(&netoring, str_lm, sizeof(str_lm));
  800.         printsub('>', &str_lm[2], sizeof(str_lm)-2);
  801.     }
  802. /*@*/    else printf("lm_do: not enough room in buffer\n");
  803.     break;
  804.     }
  805. }
  806.  
  807. lm_dont(cmd, len)
  808. unsigned char *cmd;
  809. {
  810.     if (len < 1) {
  811. /*@*/    printf("lm_dont: no command!!!\n");    /* Should not happen... */
  812.     return;
  813.     }
  814.     switch(cmd[0]) {
  815.     case LM_FORWARDMASK:
  816.     default:
  817.     /* we are always WONT, so don't respond */
  818.     break;
  819.     }
  820. }
  821.  
  822. static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE };
  823.  
  824. lm_mode(cmd, len, init)
  825. char *cmd;
  826. int len, init;
  827. {
  828.     if (len != 1)
  829.         return;
  830.     if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
  831.         return;
  832.     if (*cmd&MODE_ACK)
  833.         return;
  834.     linemode = *cmd&(MODE_MASK&~MODE_ACK);
  835.     str_lm_mode[4] = linemode;
  836.     if (!init)
  837.         str_lm_mode[4] |= MODE_ACK;
  838.     if (NETROOM() > sizeof(str_lm_mode)) {
  839.         ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
  840.         printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
  841.     }
  842. /*@*/    else printf("lm_mode: not enough room in buffer\n");
  843.     setconnmode(0);    /* set changed mode */
  844. }
  845.  
  846.  
  847.  
  848. /*
  849.  * slc()
  850.  * Handle special character suboption of LINEMODE.
  851.  */
  852.  
  853. struct spc {
  854.     cc_t val;
  855.     cc_t *valp;
  856.     char flags;    /* Current flags & level */
  857.     char mylevel;    /* Maximum level & flags */
  858. } spc_data[NSLC+1];
  859.  
  860. #define SLC_IMPORT    0
  861. #define    SLC_EXPORT    1
  862. #define SLC_RVALUE    2
  863. static int slc_mode = SLC_EXPORT;
  864.  
  865. slc_init()
  866. {
  867.     register struct spc *spcp;
  868.     extern cc_t *tcval();
  869.  
  870.     localchars = 1;
  871.     for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
  872.         spcp->val = 0;
  873.         spcp->valp = 0;
  874.         spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
  875.     }
  876.  
  877. #define    initfunc(func, flags) { \
  878.                     spcp = &spc_data[func]; \
  879.                     if (spcp->valp = tcval(func)) { \
  880.                         spcp->val = *spcp->valp; \
  881.                         spcp->mylevel = SLC_VARIABLE|flags; \
  882.                     } else { \
  883.                         spcp->val = 0; \
  884.                         spcp->mylevel = SLC_DEFAULT; \
  885.                     } \
  886.                     }
  887.  
  888.     initfunc(SLC_SYNCH, 0);
  889.     /* No BRK */
  890.     initfunc(SLC_AO, 0);
  891.     initfunc(SLC_AYT, 0);
  892.     /* No EOR */
  893.     initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
  894.     initfunc(SLC_EOF, 0);
  895.     initfunc(SLC_SUSP, SLC_FLUSHIN);
  896.     initfunc(SLC_EC, 0);
  897.     initfunc(SLC_EL, 0);
  898.     initfunc(SLC_EW, 0);
  899.     initfunc(SLC_RP, 0);
  900.     initfunc(SLC_LNEXT, 0);
  901.     initfunc(SLC_XON, 0);
  902.     initfunc(SLC_XOFF, 0);
  903.     initfunc(SLC_FORW1, 0);
  904.  
  905.     initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
  906. #undef    initfunc
  907.  
  908.     if (slc_mode == SLC_EXPORT)
  909.         slc_export();
  910.     else
  911.         slc_import(1);
  912.  
  913. }
  914.  
  915. slcstate()
  916. {
  917.     printf("Special characters are %s values\n",
  918.         slc_mode == SLC_IMPORT ? "remote default" :
  919.         slc_mode == SLC_EXPORT ? "local" :
  920.                      "remote");
  921. }
  922.  
  923. slc_mode_export()
  924. {
  925.     slc_mode = SLC_EXPORT;
  926.     if (my_state_is_will(TELOPT_LINEMODE))
  927.     slc_export();
  928. }
  929.  
  930. slc_mode_import(def)
  931. {
  932.     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
  933.     if (my_state_is_will(TELOPT_LINEMODE))
  934.     slc_import(def);
  935. }
  936.  
  937. char slc_import_val[] = {
  938.     IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
  939. };
  940. char slc_import_def[] = {
  941.     IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
  942. };
  943.  
  944. slc_import(def)
  945. int def;
  946. {
  947.     if (NETROOM() > sizeof(slc_import_val)) {
  948.     if (def) {
  949.         ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
  950.         printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
  951.     } else {
  952.         ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
  953.         printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
  954.     }
  955.     }
  956. /*@*/ else printf("slc_import: not enough room\n");
  957. }
  958.  
  959. slc_export()
  960. {
  961.     register struct spc *spcp;
  962.  
  963.     TerminalDefaultChars();
  964.  
  965.     slc_start_reply();
  966.     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
  967.     if (spcp->mylevel != SLC_NOSUPPORT) {
  968.         if (spcp->val == (cc_t)(_POSIX_VDISABLE))
  969.         spcp->flags = SLC_NOSUPPORT;
  970.         else
  971.         spcp->flags = spcp->mylevel;
  972.         if (spcp->valp)
  973.         spcp->val = *spcp->valp;
  974.         slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
  975.     }
  976.     }
  977.     slc_end_reply();
  978.     if (slc_update())
  979.     setconnmode(1);    /* set the  new character values */
  980. }
  981.  
  982. slc(cp, len)
  983. register char *cp;
  984. int len;
  985. {
  986.     register struct spc *spcp;
  987.     register int func,level;
  988.  
  989.     slc_start_reply();
  990.  
  991.     for (; len >= 3; len -=3, cp +=3) {
  992.  
  993.         func = cp[SLC_FUNC];
  994.  
  995.         if (func == 0) {
  996.             /*
  997.              * Client side: always ignore 0 function.
  998.              */
  999.             continue;
  1000.         }
  1001.         if (func > NSLC) {
  1002.             if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
  1003.                 slc_add_reply(func, SLC_NOSUPPORT, 0);
  1004.             continue;
  1005.         }
  1006.  
  1007.         spcp = &spc_data[func];
  1008.  
  1009.         level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
  1010.  
  1011.         if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
  1012.             ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
  1013.             continue;
  1014.         }
  1015.  
  1016.         if (level == (SLC_DEFAULT|SLC_ACK)) {
  1017.             /*
  1018.              * This is an error condition, the SLC_ACK
  1019.              * bit should never be set for the SLC_DEFAULT
  1020.              * level.  Our best guess to recover is to
  1021.              * ignore the SLC_ACK bit.
  1022.              */
  1023.             cp[SLC_FLAGS] &= ~SLC_ACK;
  1024.         }
  1025.  
  1026.         if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
  1027.             spcp->val = (cc_t)cp[SLC_VALUE];
  1028.             spcp->flags = cp[SLC_FLAGS];    /* include SLC_ACK */
  1029.             continue;
  1030.         }
  1031.  
  1032.         level &= ~SLC_ACK;
  1033.  
  1034.         if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
  1035.             spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
  1036.             spcp->val = (cc_t)cp[SLC_VALUE];
  1037.         }
  1038.         if (level == SLC_DEFAULT) {
  1039.             if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
  1040.                 spcp->flags = spcp->mylevel;
  1041.             else
  1042.                 spcp->flags = SLC_NOSUPPORT;
  1043.         }
  1044.         slc_add_reply(func, spcp->flags, spcp->val);
  1045.     }
  1046.     slc_end_reply();
  1047.     if (slc_update())
  1048.         setconnmode(1);    /* set the  new character values */
  1049. }
  1050.  
  1051. slc_check()
  1052. {
  1053.     register struct spc *spcp;
  1054.  
  1055.     slc_start_reply();
  1056.     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
  1057.     if (spcp->valp && spcp->val != *spcp->valp) {
  1058.         spcp->val = *spcp->valp;
  1059.         if (spcp->val == (cc_t)(_POSIX_VDISABLE))
  1060.         spcp->flags = SLC_NOSUPPORT;
  1061.         else
  1062.         spcp->flags = spcp->mylevel;
  1063.         slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
  1064.     }
  1065.     }
  1066.     slc_end_reply();
  1067.     setconnmode(1);
  1068. }
  1069.  
  1070.  
  1071. unsigned char slc_reply[128];
  1072. unsigned char *slc_replyp;
  1073. slc_start_reply()
  1074. {
  1075.     slc_replyp = slc_reply;
  1076.     *slc_replyp++ = IAC;
  1077.     *slc_replyp++ = SB;
  1078.     *slc_replyp++ = TELOPT_LINEMODE;
  1079.     *slc_replyp++ = LM_SLC;
  1080. }
  1081.  
  1082. slc_add_reply(func, flags, value)
  1083. char func;
  1084. char flags;
  1085. cc_t value;
  1086. {
  1087.     if ((*slc_replyp++ = func) == IAC)
  1088.         *slc_replyp++ = IAC;
  1089.     if ((*slc_replyp++ = flags) == IAC)
  1090.         *slc_replyp++ = IAC;
  1091.     if ((*slc_replyp++ = (unsigned char)value) == IAC)
  1092.         *slc_replyp++ = IAC;
  1093. }
  1094.  
  1095. slc_end_reply()
  1096. {
  1097.     register int len;
  1098.  
  1099.     *slc_replyp++ = IAC;
  1100.     *slc_replyp++ = SE;
  1101.     len = slc_replyp - slc_reply;
  1102.     if (len <= 6)
  1103.     return;
  1104.     if (NETROOM() > len) {
  1105.     ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
  1106.     printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
  1107.     }
  1108. /*@*/else printf("slc_end_reply: not enough room\n");
  1109. }
  1110.  
  1111. slc_update()
  1112. {
  1113.     register struct spc *spcp;
  1114.     int need_update = 0;
  1115.  
  1116.     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
  1117.         if (!(spcp->flags&SLC_ACK))
  1118.             continue;
  1119.         spcp->flags &= ~SLC_ACK;
  1120.         if (spcp->valp && (*spcp->valp != spcp->val)) {
  1121.             *spcp->valp = spcp->val;
  1122.             need_update = 1;
  1123.         }
  1124.     }
  1125.     return(need_update);
  1126. }
  1127.  
  1128. env_opt(buf, len)
  1129. register char *buf;
  1130. register int len;
  1131. {
  1132.     register char *ep = 0, *epc = 0;
  1133.     register int i;
  1134.  
  1135.     switch(buf[0]&0xff) {
  1136.     case TELQUAL_SEND:
  1137.         env_opt_start();
  1138.         if (len == 1) {
  1139.             env_opt_add(NULL);
  1140.         } else for (i = 1; i < len; i++) {
  1141.             switch (buf[i]&0xff) {
  1142.             case ENV_VALUE:
  1143.                 if (ep) {
  1144.                     *epc = 0;
  1145.                     env_opt_add(ep);
  1146.                 }
  1147.                 ep = epc = &buf[i+1];
  1148.                 break;
  1149.             case ENV_ESC:
  1150.                 i++;
  1151.                 /*FALL THROUGH*/
  1152.             default:
  1153.                 if (epc)
  1154.                     *epc++ = buf[i];
  1155.                 break;
  1156.             }
  1157.             if (ep) {
  1158.                 *epc = 0;
  1159.                 env_opt_add(ep);
  1160.             }
  1161.         }
  1162.         env_opt_end(1);
  1163.         break;
  1164.  
  1165.     case TELQUAL_IS:
  1166.     case TELQUAL_INFO:
  1167.         /* Ignore for now.  We shouldn't get it anyway. */
  1168.         break;
  1169.  
  1170.     default:
  1171.         break;
  1172.     }
  1173. }
  1174.  
  1175. #define    OPT_REPLY_SIZE    256
  1176. unsigned char *opt_reply;
  1177. unsigned char *opt_replyp;
  1178. unsigned char *opt_replyend;
  1179.  
  1180. env_opt_start()
  1181. {
  1182.     extern char *realloc();
  1183.     extern char *malloc();
  1184.  
  1185.     if (opt_reply)
  1186.         opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
  1187.     else
  1188.         opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
  1189.     if (opt_reply == NULL) {
  1190. /*@*/        printf("env_opt_start: malloc()/realloc() failed!!!\n");
  1191.         opt_reply = opt_replyp = opt_replyend = NULL;
  1192.         return;
  1193.     }
  1194.     opt_replyp = opt_reply;
  1195.     opt_replyend = opt_reply + OPT_REPLY_SIZE;
  1196.     *opt_replyp++ = IAC;
  1197.     *opt_replyp++ = SB;
  1198.     *opt_replyp++ = TELOPT_ENVIRON;
  1199.     *opt_replyp++ = TELQUAL_IS;
  1200. }
  1201.  
  1202. env_opt_start_info()
  1203. {
  1204.     env_opt_start();
  1205.     if (opt_replyp)
  1206.         opt_replyp[-1] = TELQUAL_INFO;
  1207. }
  1208.  
  1209. env_opt_add(ep)
  1210. register char *ep;
  1211. {
  1212.     register char *vp, c;
  1213.     extern char *realloc();
  1214.     extern char *env_default();
  1215.  
  1216.     if (opt_reply == NULL)        /*XXX*/
  1217.         return;            /*XXX*/
  1218.  
  1219.     if (ep == NULL || *ep == '\0') {
  1220.         env_default(1);
  1221.         while (ep = env_default(0))
  1222.             env_opt_add(ep);
  1223.         return;
  1224.     }
  1225.     vp = env_getvalue(ep);
  1226.     if (opt_replyp + (vp?strlen(vp):0) + strlen(ep) + 6 > opt_replyend) {
  1227.         register int len;
  1228.         opt_replyend += OPT_REPLY_SIZE;
  1229.         len = opt_replyend - opt_reply;
  1230.         opt_reply = (unsigned char *)realloc(opt_reply, len);
  1231.         if (opt_reply == NULL) {
  1232. /*@*/            printf("env_opt_add: realloc() failed!!!\n");
  1233.             opt_reply = opt_replyp = opt_replyend = NULL;
  1234.             return;
  1235.         }
  1236.         opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
  1237.         opt_replyend = opt_reply + len;
  1238.     }
  1239.     *opt_replyp++ = ENV_VAR;
  1240.     for (;;) {
  1241.         while (c = *ep++) {
  1242.             switch(c&0xff) {
  1243.             case IAC:
  1244.                 *opt_replyp++ = IAC;
  1245.                 break;
  1246.             case ENV_VALUE:
  1247.             case ENV_VAR:
  1248.             case ENV_ESC:
  1249.                 *opt_replyp++ = ENV_ESC;
  1250.                 break;
  1251.             }
  1252.             *opt_replyp++ = c;
  1253.         }
  1254.         if (ep = vp) {
  1255.             *opt_replyp++ = ENV_VALUE;
  1256.             vp = NULL;
  1257.         } else
  1258.             break;
  1259.     }
  1260. }
  1261.  
  1262. env_opt_end(emptyok)
  1263. register int emptyok;
  1264. {
  1265.     register int len;
  1266.  
  1267.     len = opt_replyp - opt_reply + 2;
  1268.     if (emptyok || len > 6) {
  1269.         *opt_replyp++ = IAC;
  1270.         *opt_replyp++ = SE;
  1271.         if (NETROOM() > len) {
  1272.             ring_supply_data(&netoring, opt_reply, len);
  1273.             printsub('>', &opt_reply[2], len - 2);
  1274.         }
  1275. /*@*/        else printf("slc_end_reply: not enough room\n");
  1276.     }
  1277.     if (opt_reply) {
  1278.         free(opt_reply);
  1279.         opt_reply = opt_replyp = opt_replyend = NULL;
  1280.     }
  1281. }
  1282.  
  1283.  
  1284.  
  1285. int
  1286. telrcv()
  1287. {
  1288.     register int c;
  1289.     register int scc;
  1290.     register char *sbp;
  1291.     int count;
  1292.     int returnValue = 0;
  1293.  
  1294.     scc = 0;
  1295.     count = 0;
  1296.     while (TTYROOM() > 2) {
  1297.     if (scc == 0) {
  1298.         if (count) {
  1299.         ring_consumed(&netiring, count);
  1300.         returnValue = 1;
  1301.         count = 0;
  1302.         }
  1303.         sbp = netiring.consume;
  1304.         scc = ring_full_consecutive(&netiring);
  1305.         if (scc == 0) {
  1306.         /* No more data coming in */
  1307.         break;
  1308.         }
  1309.     }
  1310.  
  1311.     c = *sbp++ & 0xff, scc--; count++;
  1312.  
  1313.     switch (telrcv_state) {
  1314.  
  1315.     case TS_CR:
  1316.         telrcv_state = TS_DATA;
  1317.         if (c == '\0') {
  1318.         break;    /* Ignore \0 after CR */
  1319.         }
  1320.         else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
  1321.         TTYADD(c);
  1322.         break;
  1323.         }
  1324.         /* Else, fall through */
  1325.  
  1326.     case TS_DATA:
  1327.         if (c == IAC) {
  1328.         telrcv_state = TS_IAC;
  1329.         break;
  1330.         }
  1331.             /*
  1332.              * The 'crmod' hack (see following) is needed
  1333.              * since we can't * set CRMOD on output only.
  1334.              * Machines like MULTICS like to send \r without
  1335.              * \n; since we must turn off CRMOD to get proper
  1336.              * input, the mapping is done here (sigh).
  1337.              */
  1338.         if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
  1339.         if (scc > 0) {
  1340.             c = *sbp&0xff;
  1341.             if (c == 0) {
  1342.             sbp++, scc--; count++;
  1343.             /* a "true" CR */
  1344.             TTYADD('\r');
  1345.             } else if (my_want_state_is_dont(TELOPT_ECHO) &&
  1346.                     (c == '\n')) {
  1347.             sbp++, scc--; count++;
  1348.             TTYADD('\n');
  1349.             } else {
  1350.             TTYADD('\r');
  1351.             if (crmod) {
  1352.                 TTYADD('\n');
  1353.             }
  1354.             }
  1355.         } else {
  1356.             telrcv_state = TS_CR;
  1357.             TTYADD('\r');
  1358.             if (crmod) {
  1359.                 TTYADD('\n');
  1360.             }
  1361.         }
  1362.         } else {
  1363.         TTYADD(c);
  1364.         }
  1365.         continue;
  1366.  
  1367.     case TS_IAC:
  1368. process_iac:
  1369.         switch (c) {
  1370.         
  1371.         case WILL:
  1372.         telrcv_state = TS_WILL;
  1373.         continue;
  1374.  
  1375.         case WONT:
  1376.         telrcv_state = TS_WONT;
  1377.         continue;
  1378.  
  1379.         case DO:
  1380.         telrcv_state = TS_DO;
  1381.         continue;
  1382.  
  1383.         case DONT:
  1384.         telrcv_state = TS_DONT;
  1385.         continue;
  1386.  
  1387.         case DM:
  1388.             /*
  1389.              * We may have missed an urgent notification,
  1390.              * so make sure we flush whatever is in the
  1391.              * buffer currently.
  1392.              */
  1393.         printoption("RCVD", "IAC", DM);
  1394.         SYNCHing = 1;
  1395.         (void) ttyflush(1);
  1396.         SYNCHing = stilloob();
  1397.         settimer(gotDM);
  1398.         break;
  1399.  
  1400.         case SB:
  1401.         SB_CLEAR();
  1402.         telrcv_state = TS_SB;
  1403.         printoption("RCVD", "IAC", SB);
  1404.         continue;
  1405.  
  1406.         case IAC:
  1407.         TTYADD(IAC);
  1408.         break;
  1409.  
  1410.         case NOP:
  1411.  
  1412.         default:
  1413.         printoption("RCVD", "IAC", c);
  1414.         break;
  1415.         }
  1416.         telrcv_state = TS_DATA;
  1417.         continue;
  1418.  
  1419.     case TS_WILL:
  1420.         printoption("RCVD", "will", c);
  1421.         willoption(c);
  1422.         telrcv_state = TS_DATA;
  1423.         continue;
  1424.  
  1425.     case TS_WONT:
  1426.         printoption("RCVD", "wont", c);
  1427.         wontoption(c);
  1428.         telrcv_state = TS_DATA;
  1429.         continue;
  1430.  
  1431.     case TS_DO:
  1432.         printoption("RCVD", "do", c);
  1433.         dooption(c);
  1434.         if (c == TELOPT_NAWS) {
  1435.         sendnaws();
  1436.         } else if (c == TELOPT_LFLOW) {
  1437.         localflow = 1;
  1438.         setcommandmode();
  1439.         setconnmode(0);
  1440.         }
  1441.         telrcv_state = TS_DATA;
  1442.         continue;
  1443.  
  1444.     case TS_DONT:
  1445.         printoption("RCVD", "dont", c);
  1446.         dontoption(c);
  1447.         flushline = 1;
  1448.         setconnmode(0);    /* set new tty mode (maybe) */
  1449.         telrcv_state = TS_DATA;
  1450.         continue;
  1451.  
  1452.     case TS_SB:
  1453.         if (c == IAC) {
  1454.         telrcv_state = TS_SE;
  1455.         } else {
  1456.         SB_ACCUM(c);
  1457.         }
  1458.         continue;
  1459.  
  1460.     case TS_SE:
  1461.         if (c != SE) {
  1462.         if (c != IAC) {
  1463.             /*
  1464.              * This is an error.  We only expect to get
  1465.              * "IAC IAC" or "IAC SE".  Several things may
  1466.              * have happend.  An IAC was not doubled, the
  1467.              * IAC SE was left off, or another option got
  1468.              * inserted into the suboption are all possibilities.
  1469.              * If we assume that the IAC was not doubled,
  1470.              * and really the IAC SE was left off, we could
  1471.              * get into an infinate loop here.  So, instead,
  1472.              * we terminate the suboption, and process the
  1473.              * partial suboption if we can.
  1474.              */
  1475.             SB_TERM();
  1476.             SB_ACCUM(IAC);
  1477.             SB_ACCUM(c);
  1478.             printoption("In SUBOPTION processing, RCVD", "IAC", c);
  1479.             suboption();    /* handle sub-option */
  1480.             telrcv_state = TS_IAC;
  1481.             goto process_iac;
  1482.         }
  1483.         SB_ACCUM(c);
  1484.         telrcv_state = TS_SB;
  1485.         } else {
  1486.         SB_TERM();
  1487.         SB_ACCUM(IAC);
  1488.         SB_ACCUM(SE);
  1489.         suboption();    /* handle sub-option */
  1490.         telrcv_state = TS_DATA;
  1491.         }
  1492.     }
  1493.     }
  1494.     if (count)
  1495.     ring_consumed(&netiring, count);
  1496.     return returnValue||count;
  1497. }
  1498.  
  1499. static int
  1500. telsnd()
  1501. {
  1502.     int tcc;
  1503.     int count;
  1504.     int returnValue = 0;
  1505.     char *tbp;
  1506.  
  1507.     tcc = 0;
  1508.     count = 0;
  1509.     while (NETROOM() > 2) {
  1510.     register int sc;
  1511.     register int c;
  1512.  
  1513.     if (tcc == 0) {
  1514.         if (count) {
  1515.         ring_consumed(&ttyiring, count);
  1516.         returnValue = 1;
  1517.         count = 0;
  1518.         }
  1519.         tbp = ttyiring.consume;
  1520.         tcc = ring_full_consecutive(&ttyiring);
  1521.         if (tcc == 0) {
  1522.         break;
  1523.         }
  1524.     }
  1525.     c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
  1526.     if (sc == escape) {
  1527.         /*
  1528.          * Double escape is a pass through of a single escape character.
  1529.          */
  1530.         if (tcc && strip(*tbp) == escape) {
  1531.         tbp++;
  1532.         tcc--;
  1533.         count++;
  1534.         } else {
  1535.         command(0, tbp, tcc);
  1536.         count += tcc;
  1537.         tcc = 0;
  1538.         flushline = 1;
  1539.         break;
  1540.         }
  1541.     }
  1542.     if (my_want_state_is_wont(TELOPT_BINARY)) {
  1543.         switch (c) {
  1544.         case '\n':
  1545.             /*
  1546.              * If we are in CRMOD mode (\r ==> \n)
  1547.              * on our local machine, then probably
  1548.              * a newline (unix) is CRLF (TELNET).
  1549.              */
  1550.         if (MODE_LOCAL_CHARS(globalmode)) {
  1551.             NETADD('\r');
  1552.         }
  1553.         NETADD('\n');
  1554.         flushline = 1;
  1555.         break;
  1556.         case '\r':
  1557.         if (!crlf) {
  1558.             NET2ADD('\r', '\0');
  1559.         } else {
  1560.             NET2ADD('\r', '\n');
  1561.         }
  1562.         flushline = 1;
  1563.         break;
  1564.         case IAC:
  1565.         NET2ADD(IAC, IAC);
  1566.         break;
  1567.         default:
  1568.         NETADD(c);
  1569.         break;
  1570.         }
  1571.     } else if (c == IAC) {
  1572.         NET2ADD(IAC, IAC);
  1573.     } else {
  1574.         NETADD(c);
  1575.     }
  1576.     }
  1577.     if (count)
  1578.     ring_consumed(&ttyiring, count);
  1579.     return returnValue||count;        /* Non-zero if we did anything */
  1580. }
  1581.  
  1582. /*
  1583.  * Scheduler()
  1584.  *
  1585.  * Try to do something.
  1586.  *
  1587.  * If we do something useful, return 1; else return 0.
  1588.  *
  1589.  */
  1590.  
  1591.  
  1592. int
  1593. Scheduler(block)
  1594. int    block;            /* should we block in the select ? */
  1595. {
  1596.         /* One wants to be a bit careful about setting returnValue
  1597.          * to one, since a one implies we did some useful work,
  1598.          * and therefore probably won't be called to block next
  1599.          * time (TN3270 mode only).
  1600.          */
  1601.     int returnValue;
  1602.     int netin, netout, netex, ttyin, ttyout;
  1603.  
  1604.     /* Check for break signals */
  1605.  
  1606.     if (SetSignal(0L,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D) &
  1607.         (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D))
  1608.     quit();
  1609.  
  1610.     /* Decide which rings should be processed */
  1611.  
  1612.     netout = ring_full_count(&netoring) &&
  1613.         (flushline ||
  1614.         (my_want_state_is_wont(TELOPT_LINEMODE)
  1615.         ) ||
  1616.             my_want_state_is_will(TELOPT_BINARY));
  1617.     ttyout = ring_full_count(&ttyoring);
  1618.  
  1619.     ttyin = ring_empty_count(&ttyiring);
  1620.  
  1621.     netin = !ISend && ring_empty_count(&netiring);
  1622.  
  1623.     netex = !SYNCHing;
  1624.  
  1625.     /* Call to system code to process rings */
  1626.  
  1627.     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
  1628.  
  1629.     /* Now, look at the input rings, looking for work to do. */
  1630.  
  1631.     if (ring_full_count(&ttyiring)) {
  1632.         returnValue |= telsnd();
  1633.     }
  1634.  
  1635.     if (ring_full_count(&netiring)) {
  1636.     returnValue |= telrcv();
  1637.     }
  1638.     return returnValue;
  1639. }
  1640.  
  1641. /*
  1642.  * Select from tty and network...
  1643.  */
  1644. void
  1645. telnet()
  1646. {
  1647.     sys_telnet_init();
  1648.  
  1649.     if (telnetport) {
  1650.     send_do(TELOPT_SGA, 1);
  1651.     send_will(TELOPT_TTYPE, 1);
  1652.     send_will(TELOPT_NAWS, 1);
  1653.     send_will(TELOPT_TSPEED, 1);
  1654.     send_will(TELOPT_LFLOW, 1);
  1655.     send_will(TELOPT_LINEMODE, 1);
  1656.     send_do(TELOPT_STATUS, 1);
  1657.     if (env_getvalue("DISPLAY"))
  1658.         send_will(TELOPT_XDISPLOC, 1);
  1659.     send_will(TELOPT_ENVIRON, 1);
  1660.     }
  1661.  
  1662.     for (;;) {
  1663.     int schedValue;
  1664.  
  1665.     while ((schedValue = Scheduler(0)) != 0) {
  1666.         if (schedValue == -1) {
  1667.         setcommandmode();
  1668.         return;
  1669.         }
  1670.     }
  1671.  
  1672.     if (Scheduler(1) == -1) {
  1673.         setcommandmode();
  1674.         return;
  1675.     }
  1676.     }
  1677. }
  1678.  
  1679. /*
  1680.  * netclear()
  1681.  *
  1682.  *    We are about to do a TELNET SYNCH operation.  Clear
  1683.  * the path to the network.
  1684.  *
  1685.  *    Things are a bit tricky since we may have sent the first
  1686.  * byte or so of a previous TELNET command into the network.
  1687.  * So, we have to scan the network buffer from the beginning
  1688.  * until we are up to where we want to be.
  1689.  *
  1690.  *    A side effect of what we do, just to keep things
  1691.  * simple, is to clear the urgent data pointer.  The principal
  1692.  * caller should be setting the urgent data pointer AFTER calling
  1693.  * us in any case.
  1694.  */
  1695.  
  1696. static void
  1697. netclear()
  1698. {
  1699. }
  1700.  
  1701. /*
  1702.  * These routines add various telnet commands to the data stream.
  1703.  */
  1704.  
  1705. static void
  1706. doflush()
  1707. {
  1708.     NET2ADD(IAC, DO);
  1709.     NETADD(TELOPT_TM);
  1710.     flushline = 1;
  1711.     flushout = 1;
  1712.     (void) ttyflush(1);            /* Flush/drop output */
  1713.     /* do printoption AFTER flush, otherwise the output gets tossed... */
  1714.     printoption("SENT", "do", TELOPT_TM);
  1715. }
  1716.  
  1717. void
  1718. xmitAO()
  1719. {
  1720.     NET2ADD(IAC, AO);
  1721.     printoption("SENT", "IAC", AO);
  1722.     if (autoflush) {
  1723.     doflush();
  1724.     }
  1725. }
  1726.  
  1727.  
  1728. void
  1729. xmitEL()
  1730. {
  1731.     NET2ADD(IAC, EL);
  1732.     printoption("SENT", "IAC", EL);
  1733. }
  1734.  
  1735. void
  1736. xmitEC()
  1737. {
  1738.     NET2ADD(IAC, EC);
  1739.     printoption("SENT", "IAC", EC);
  1740. }
  1741.  
  1742.  
  1743. void
  1744. dosynch()
  1745. {
  1746.     netclear();            /* clear the path to the network */
  1747.     NETADD(IAC);
  1748.     setneturg();
  1749.     NETADD(DM);
  1750.     printoption("SENT", "IAC", DM);
  1751.  
  1752.     return;
  1753. }
  1754.  
  1755. void
  1756. get_status()
  1757. {
  1758.     char tmp[16];
  1759.     register char *cp;
  1760.  
  1761.     if (my_want_state_is_dont(TELOPT_STATUS)) {
  1762.     printf("Remote side does not support STATUS option\n");
  1763.     return;
  1764.     }
  1765.     if (!showoptions)
  1766.     printf("You will not see the response unless you set \"options\"\n");
  1767.  
  1768.     cp = tmp;
  1769.  
  1770.     *cp++ = IAC;
  1771.     *cp++ = SB;
  1772.     *cp++ = TELOPT_STATUS;
  1773.     *cp++ = TELQUAL_SEND;
  1774.     *cp++ = IAC;
  1775.     *cp++ = SE;
  1776.     if (NETROOM() >= cp - tmp) {
  1777.     ring_supply_data(&netoring, tmp, cp-tmp);
  1778.     printsub('>', tmp+2, cp - tmp - 2);
  1779.     }
  1780. }
  1781.  
  1782. void
  1783. intp()
  1784. {
  1785.     NET2ADD(IAC, IP);
  1786.     printoption("SENT", "IAC", IP);
  1787.     flushline = 1;
  1788.     if (autoflush) {
  1789.     doflush();
  1790.     }
  1791.     if (autosynch) {
  1792.     dosynch();
  1793.     }
  1794. }
  1795.  
  1796. void
  1797. sendbrk()
  1798. {
  1799.     NET2ADD(IAC, BREAK);
  1800.     printoption("SENT", "IAC", BREAK);
  1801.     flushline = 1;
  1802.     if (autoflush) {
  1803.     doflush();
  1804.     }
  1805.     if (autosynch) {
  1806.     dosynch();
  1807.     }
  1808. }
  1809.  
  1810. void
  1811. sendabort()
  1812. {
  1813.     NET2ADD(IAC, ABORT);
  1814.     printoption("SENT", "IAC", ABORT);
  1815.     flushline = 1;
  1816.     if (autoflush) {
  1817.     doflush();
  1818.     }
  1819.     if (autosynch) {
  1820.     dosynch();
  1821.     }
  1822. }
  1823.  
  1824. void
  1825. sendsusp()
  1826. {
  1827.     NET2ADD(IAC, SUSP);
  1828.     printoption("SENT", "IAC", SUSP);
  1829.     flushline = 1;
  1830.     if (autoflush) {
  1831.     doflush();
  1832.     }
  1833.     if (autosynch) {
  1834.     dosynch();
  1835.     }
  1836. }
  1837.  
  1838. void
  1839. sendeof()
  1840. {
  1841.     NET2ADD(IAC, xEOF);
  1842.     printoption("SENT", "IAC", xEOF);
  1843. }
  1844.  
  1845. void
  1846. sendayt()
  1847. {
  1848.     NET2ADD(IAC, AYT);
  1849.     printoption("SENT", "IAC", AYT);
  1850. }
  1851.  
  1852. /*
  1853.  * Send a window size update to the remote system.
  1854.  */
  1855.  
  1856. void
  1857. sendnaws()
  1858. {
  1859.     long rows, cols;
  1860.     unsigned char tmp[16];
  1861.     register unsigned char *cp;
  1862.  
  1863.     if (my_state_is_wont(TELOPT_NAWS))
  1864.     return;
  1865.  
  1866. #define    PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
  1867.                 if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
  1868.  
  1869.     if (TerminalWindowSize(&rows, &cols) == 0) {    /* Failed */
  1870.     return;
  1871.     }
  1872.  
  1873.     cp = tmp;
  1874.  
  1875.     *cp++ = IAC;
  1876.     *cp++ = SB;
  1877.     *cp++ = TELOPT_NAWS;
  1878.     PUTSHORT(cp, cols);
  1879.     PUTSHORT(cp, rows);
  1880.     *cp++ = IAC;
  1881.     *cp++ = SE;
  1882.     if (NETROOM() >= cp - tmp) {
  1883.     ring_supply_data(&netoring, tmp, cp-tmp);
  1884.     printsub('>', tmp+2, cp - tmp - 2);
  1885.     }
  1886. }
  1887.  
  1888. tel_enter_binary(rw)
  1889. int rw;
  1890. {
  1891.     if (rw&1)
  1892.     send_do(TELOPT_BINARY, 1);
  1893.     if (rw&2)
  1894.     send_will(TELOPT_BINARY, 1);
  1895. }
  1896.  
  1897. tel_leave_binary(rw)
  1898. int rw;
  1899. {
  1900.     if (rw&1)
  1901.     send_dont(TELOPT_BINARY, 1);
  1902.     if (rw&2)
  1903.     send_wont(TELOPT_BINARY, 1);
  1904. }
  1905.